xenpm: Allow user to enable/disable dbs governor turbo mode.
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 8 Feb 2010 08:48:40 +0000 (08:48 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 8 Feb 2010 08:48:40 +0000 (08:48 +0000)
Signed-off-by: Lu Guanqun <guanqun.lu@intel.com>
tools/libxc/xc_pm.c
tools/libxc/xenctrl.h
tools/misc/xenpm.c
xen/drivers/acpi/pmstat.c
xen/drivers/cpufreq/cpufreq_ondemand.c
xen/drivers/cpufreq/utility.c
xen/include/acpi/cpufreq/cpufreq.h
xen/include/public/sysctl.h

index bb9a80c9e2f1b3a41b0ae6c26f4bbb734a1ee88c..7d588346d568a8148dfb05b81017ebeac6f518f8 100644 (file)
@@ -425,3 +425,28 @@ int xc_set_cpuidle_max_cstate(int xc_handle, uint32_t value)
     return do_sysctl(xc_handle, &sysctl);
 }
 
+int xc_enable_turbo(int xc_handle, int cpuid)
+{
+    DECLARE_SYSCTL;
+
+    if ( xc_handle < 0 )
+        return -EINVAL;
+
+    sysctl.cmd = XEN_SYSCTL_pm_op;
+    sysctl.u.pm_op.cmd = XEN_SYSCTL_pm_op_enable_turbo;
+    sysctl.u.pm_op.cpuid = cpuid;
+    return do_sysctl(xc_handle, &sysctl);
+}
+
+int xc_disable_turbo(int xc_handle, int cpuid)
+{
+    DECLARE_SYSCTL;
+
+    if ( xc_handle < 0 )
+        return -EINVAL;
+
+    sysctl.cmd = XEN_SYSCTL_pm_op;
+    sysctl.u.pm_op.cmd = XEN_SYSCTL_pm_op_disable_turbo;
+    sysctl.u.pm_op.cpuid = cpuid;
+    return do_sysctl(xc_handle, &sysctl);
+}
index ca6b89c09e1ae9acfc360687cb250bab6f4dab92..77566e27ff55d2c14058e40bd9d1ab5f264e2ce1 100644 (file)
@@ -1312,6 +1312,8 @@ int xc_get_vcpu_migration_delay(int xc_handle, uint32_t *value);
 int xc_get_cpuidle_max_cstate(int xc_handle, uint32_t *value);
 int xc_set_cpuidle_max_cstate(int xc_handle, uint32_t value);
 
+int xc_enable_turbo(int xc_handle, int cpuid);
+int xc_disable_turbo(int xc_handle, int cpuid);
 /**
  * tmem operations
  */
index 015d80a5b9dcf6c005ecece5b9199657b2f5f1c5..b795adc9715ab4ac30df1225d755d84757327722 100644 (file)
@@ -62,6 +62,8 @@ void show_help(void)
             " set-max-cstate        <num>         set the C-State limitation (<num> >= 0)\n"
             " start [seconds]                     start collect Cx/Px statistics,\n"
             "                                     output after CTRL-C or SIGINT or several seconds.\n"
+            " enable-turbo-mode     [cpuid]       enable Turbo Mode in DBS governor.\n"
+            " disable-turbo-mode    [cpuid]       disable Turbo Mode in DBS governor.\n"
             );
 }
 /* wrapper function */
@@ -527,6 +529,8 @@ static void print_cpufreq_para(int cpuid, struct xc_get_cpufreq_para *p_cpufreq)
                p_cpufreq->u.ondemand.sampling_rate);
         printf("    up_threshold     : %u\n",
                p_cpufreq->u.ondemand.up_threshold);
+        printf("    turbo mode       : %s\n",
+               p_cpufreq->u.ondemand.turbo_enabled ? "enabled" : "disabled");
     }
 
     printf("scaling_avail_freq   :");
@@ -951,6 +955,50 @@ void set_max_cstate_func(int argc, char *argv[])
     return;
 }
 
+void enable_turbo_mode(int argc, char *argv[])
+{
+    int cpuid = -1;
+
+    if ( argc > 0 && sscanf(argv[0], "%d", &cpuid) != 1 )
+        cpuid = -1;
+
+    if ( cpuid >= max_cpu_nr )
+        cpuid = -1;
+
+    if ( cpuid < 0 )
+    {
+        /* enable turbo modes on all cpus,
+         * only make effects on dbs governor */
+        int i;
+        for ( i = 0; i < max_cpu_nr; i++ )
+            xc_enable_turbo(xc_fd, i);
+    }
+    else
+        xc_enable_turbo(xc_fd, cpuid);
+}
+
+void disable_turbo_mode(int argc, char *argv[])
+{
+    int cpuid = -1;
+
+    if ( argc > 0 && sscanf(argv[0], "%d", &cpuid) != 1 )
+        cpuid = -1;
+
+    if ( cpuid >= max_cpu_nr )
+        cpuid = -1;
+
+    if ( cpuid < 0 )
+    {
+        /* disable turbo modes on all cpus,
+         * only make effects on dbs governor */
+        int i;
+        for ( i = 0; i < max_cpu_nr; i++ )
+            xc_disable_turbo(xc_fd, i);
+    }
+    else
+        xc_disable_turbo(xc_fd, cpuid);
+}
+
 struct {
     const char *name;
     void (*function)(int argc, char *argv[]);
@@ -971,6 +1019,8 @@ struct {
     { "get-vcpu-migration-delay", get_vcpu_migration_delay_func},
     { "set-vcpu-migration-delay", set_vcpu_migration_delay_func},
     { "set-max-cstate", set_max_cstate_func},
+    { "enable-turbo-mode", enable_turbo_mode },
+    { "disable-turbo-mode", disable_turbo_mode },
 };
 
 int main(int argc, char *argv[])
index fedd77b90669d41eddf3c443f7c84fc4038ed538..f1520004899714f6160f35482070e2224d2f0120 100644 (file)
@@ -298,7 +298,9 @@ static int get_cpufreq_para(struct xen_sysctl_pm_op *op)
             &op->u.get_para.u.ondemand.sampling_rate_max,
             &op->u.get_para.u.ondemand.sampling_rate_min,
             &op->u.get_para.u.ondemand.sampling_rate,
-            &op->u.get_para.u.ondemand.up_threshold); 
+            &op->u.get_para.u.ondemand.up_threshold);
+        op->u.get_para.u.ondemand.turbo_enabled =
+            cpufreq_dbs_get_turbo_status(op->cpuid);
     }
 
     return ret;
@@ -549,6 +551,18 @@ int do_pm_op(struct xen_sysctl_pm_op *op)
         break;
     }
 
+    case XEN_SYSCTL_pm_op_enable_turbo:
+    {
+        cpufreq_dbs_enable_turbo(op->cpuid);
+        break;
+    }
+
+    case XEN_SYSCTL_pm_op_disable_turbo:
+    {
+        cpufreq_dbs_disable_turbo(op->cpuid);
+        break;
+    }
+
     default:
         printk("not defined sub-hypercall @ do_pm_op\n");
         ret = -ENOSYS;
index 2e5a1c5832216843a001946a480f08edcad4a0c0..799a377f539eda5cd90b4a926ab0763d65e0b4cd 100644 (file)
@@ -58,6 +58,9 @@ static struct dbs_tuners {
 
 static struct timer dbs_timer[NR_CPUS];
 
+/* Turbo Mode */
+static int turbo_detected = 0;
+
 int write_ondemand_sampling_rate(unsigned int sampling_rate)
 {
     if ( (sampling_rate > MAX_SAMPLING_RATE / MICROSECS(1)) ||
@@ -100,15 +103,21 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
     uint64_t cur_ns, total_ns;
     uint64_t max_load_freq = 0;
     struct cpufreq_policy *policy;
+    unsigned int max;
     unsigned int j;
 
     if (!this_dbs_info->enable)
         return;
 
     policy = this_dbs_info->cur_policy;
+    max = policy->max;
+    if (turbo_detected && !this_dbs_info->turbo_enabled) {
+        if (max > policy->cpuinfo.second_max_freq)
+            max = policy->cpuinfo.second_max_freq;
+    }
 
     if (unlikely(policy->resume)) {
-        __cpufreq_driver_target(policy, policy->max,CPUFREQ_RELATION_H);
+        __cpufreq_driver_target(policy, max,CPUFREQ_RELATION_H);
         return;
     }
 
@@ -145,9 +154,9 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
     /* Check for frequency increase */
     if (max_load_freq > dbs_tuners_ins.up_threshold * policy->cur) {
         /* if we are already at full speed then break out early */
-        if (policy->cur == policy->max)
+        if (policy->cur == max)
             return;
-        __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H);
+        __cpufreq_driver_target(policy, max, CPUFREQ_RELATION_H);
         return;
     }
 
@@ -265,6 +274,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event)
             } else
                 dbs_tuners_ins.sampling_rate = usr_sampling_rate;
         }
+        this_dbs_info->turbo_enabled = 1;
         dbs_timer_init(this_dbs_info);
 
         break;
@@ -335,6 +345,11 @@ struct cpufreq_governor cpufreq_gov_dbs = {
 
 static int __init cpufreq_gov_dbs_init(void)
 {
+    unsigned int eax = cpuid_eax(6);
+    if ( eax & 0x2 ) {
+        turbo_detected = 1;
+        printk(XENLOG_INFO "Turbo Mode detected!\n");
+    }
     return cpufreq_register_governor(&cpufreq_gov_dbs);
 }
 __initcall(cpufreq_gov_dbs_init);
@@ -379,3 +394,19 @@ void cpufreq_dbs_timer_resume(void)
         }
     }
 }
+
+void cpufreq_dbs_enable_turbo(int cpuid)
+{
+    per_cpu(cpu_dbs_info, cpuid).turbo_enabled = 1;
+}
+
+void cpufreq_dbs_disable_turbo(int cpuid)
+{
+    per_cpu(cpu_dbs_info, cpuid).turbo_enabled = 0;
+}
+
+unsigned int cpufreq_dbs_get_turbo_status(int cpuid)
+{
+    return turbo_detected && per_cpu(cpu_dbs_info, cpuid).turbo_enabled;
+}
+
index 5daffedf593e958b93bffe81d47472e801f4269f..c3259d1926d702636114da2ce462c1d948efca1e 100644 (file)
@@ -208,6 +208,7 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
 {
     unsigned int min_freq = ~0;
     unsigned int max_freq = 0;
+    unsigned int second_max_freq = 0;
     unsigned int i;
 
     for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
@@ -219,9 +220,21 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
         if (freq > max_freq)
             max_freq = freq;
     }
+    for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
+        unsigned int freq = table[i].frequency;
+        if (freq == CPUFREQ_ENTRY_INVALID || freq == max_freq)
+            continue;
+        if (freq > second_max_freq)
+            second_max_freq = freq;
+    }
+    if (second_max_freq == 0)
+        second_max_freq = max_freq;
+    printk(XENLOG_INFO "max_freq: %u    second_max_freq: %u\n",
+           max_freq, second_max_freq);
 
     policy->min = policy->cpuinfo.min_freq = min_freq;
     policy->max = policy->cpuinfo.max_freq = max_freq;
+    policy->cpuinfo.second_max_freq = second_max_freq;
 
     if (policy->min == ~0)
         return -EINVAL;
index 0cfda5d653499f25af7b455142e906a6db662c99..1f0506dd937d03a4172df9a63cec0c0215c6f683 100644 (file)
@@ -33,6 +33,7 @@ struct acpi_cpufreq_data {
 
 struct cpufreq_cpuinfo {
     unsigned int        max_freq;
+    unsigned int        second_max_freq;    /* P1 if Turbo Mode is on */
     unsigned int        min_freq;
     unsigned int        transition_latency; /* in 10^(-9) s = nanoseconds */
 };
@@ -222,6 +223,7 @@ struct cpu_dbs_info_s {
     int cpu;
     unsigned int enable:1;
     unsigned int stoppable:1;
+    unsigned int turbo_enabled:1;
 };
 
 int cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event);
@@ -236,4 +238,8 @@ int write_userspace_scaling_setspeed(unsigned int cpu, unsigned int freq);
 
 void cpufreq_dbs_timer_suspend(void);
 void cpufreq_dbs_timer_resume(void);
+
+void cpufreq_dbs_enable_turbo(int cpuid);
+void cpufreq_dbs_disable_turbo(int cpuid);
+unsigned int cpufreq_dbs_get_turbo_status(int cpuid);
 #endif /* __XEN_CPUFREQ_PM_H__ */
index bc02643ad73a25dca01558e25f05d8320dee1141..b6511489b9ceb913d3704f37ef015e6c0388caa4 100644 (file)
@@ -298,6 +298,7 @@ struct xen_ondemand {
 
     uint32_t sampling_rate;
     uint32_t up_threshold;
+    uint32_t turbo_enabled;
 };
 typedef struct xen_ondemand xen_ondemand_t;
 
@@ -390,6 +391,10 @@ struct xen_sysctl_pm_op {
     #define XEN_SYSCTL_pm_op_set_vcpu_migration_delay   0x24
     #define XEN_SYSCTL_pm_op_get_vcpu_migration_delay   0x25
 
+    /* enable/disable turbo mode when in dbs governor */
+    #define XEN_SYSCTL_pm_op_enable_turbo               0x26
+    #define XEN_SYSCTL_pm_op_disable_turbo              0x27
+
     uint32_t cmd;
     uint32_t cpuid;
     union {